package com.zrf.testchatgpt.shiro.filer;

import com.alibaba.fastjson.JSONObject;
import com.zrf.testchatgpt.shiro.token.LoginToken;
import com.zrf.testchatgpt.constant.Constant;
import com.zrf.testchatgpt.shiro.util.JwtTokenUtil;
import com.zrf.testchatgpt.util.RedisCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;

@Slf4j
public class AuthcFiler extends AuthenticatingFilter {

    @Autowired
    JwtTokenUtil jwtTokenUtil;
    @Autowired
    RedisCacheUtil redisCacheUtil;
    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        //获取请求token
        String token = getRequestToken((HttpServletRequest) servletRequest);

        if(StringUtils.isBlank(token)){
            return null;
        }

        return new LoginToken();
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)  {
        Subject subject = this.getSubject(request, response);
        String[] perms = (String[]) ((String[]) mappedValue);
        boolean isPermitted = true;
        if (perms != null && perms.length > 0) {
            if (perms.length == 1) {
                if (!isOneOfPermitted(perms[0], subject)) {
                    isPermitted = false;
                }
            } else if (!isAllPermitted(perms,subject)) {
                isPermitted = false;
            }
        }
        return isPermitted;
//        return false;
    }

    /**
     * 以“，”分割的权限为并列关系的权限控制，分别对每个权限字符串进行“|”分割解析
     * 若并列关系的权限有一个不满足则返回false
     *
     * @param permStrArray 以","分割的权限集合
     * @param subject      当前用户的登录信息
     * @return 是否拥有该权限
     */
    private boolean isAllPermitted(String[] permStrArray, Subject subject) {
        boolean isPermitted = true;
        for (int index = 0, len = permStrArray.length; index < len; index++) {
            if (!isOneOfPermitted(permStrArray[index], subject)) {
                isPermitted = false;
            }
        }
        return isPermitted;
    }

    /**
     * 判断以“|”分割的权限有一个满足的就返回true，表示权限的或者关系
     *
     * @param permStr 权限数组种中的一个字符串
     * @param subject 当前用户信息
     * @return 是否有权限
     */
    private boolean isOneOfPermitted(String permStr, Subject subject) {
        boolean isPermitted = false;
        String[] permArr = permStr.split("\\|");
        if (permArr.length > 0) {
            for (int index = 0, len = permArr.length; index < len; index++) {
                if (subject.isPermitted(permArr[index])) {
                    isPermitted = true;
                }
            }
        }
        return isPermitted;
    }
    /**
     * 返回结果为true表明登录通过
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        String token = getRequestToken((HttpServletRequest) request);
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        if(StringUtils.isBlank(token)){

            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setContentType("application/json;charset=UTF-8");
            httpResponse.setStatus(200);
            httpResponse.setHeader("Access-Control-Allow-Origin","*");

//            String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token"));
            HashMap<String,Object> map=new HashMap<>();
            map.put("code", HttpStatus.SC_UNAUTHORIZED);
            map.put("msg"," token为空");
            JSONObject json = new JSONObject(map);
            httpResponse.getWriter().print(json);
            return false;
        }
        if (!jwtTokenUtil.validateToken(token)|| redisCacheUtil.hasKey(Constant.JWT_ACCESS_TOKEN_BLACKLIST+token)){
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setContentType("application/json;charset=UTF-8");
            httpResponse.setStatus(200);
            httpResponse.setHeader("Access-Control-Allow-Origin","*");

//            String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token"));
            HashMap<String,Object> map=new HashMap<>();
            map.put("code",500);
            map.put("msg","token失效");
            JSONObject json = new JSONObject(map);
            httpResponse.getWriter().print(json);
            return false;
        }

        return executeLogin(request, response);
    }

    private String getRequestToken(HttpServletRequest httpRequest){
        //从header中获取token
        String token = httpRequest.getHeader("accesstoken");
        log.info("从请求头中获取的token:"+token);
        //如果header中不存在token，则从参数中获取token
        if(StringUtils.isBlank(token)){
            token = httpRequest.getParameter("accesstoken");
        }

        return token;
    }
}
